import {
  FC,
  isValidElement,
  ReactNode,
  useEffect,
  useRef,
  useState,
  MouseEvent,
  cloneElement,
} from 'react';
import { Tooltip, ButtonProps, Button, Progress } from 'antd';
import { useDrag, useDrop } from 'react-dnd';

import CSSMotion from 'rc-motion';

import { UploadFile } from 'antd/lib/upload/interface';
import { DynamicObjectAny } from '@/typings';
import { useIntl } from 'umi';
import classNames from 'classnames';

import { DeleteOutlined, DownloadOutlined, EyeOutlined, CopyOutlined } from '@ant-design/icons';
import { IMG_TYPE } from './modal/view-container';

const type = 'DragAbleUploadList';

const prefixCls = 'ant-upload';

export const NO_REMOVE_FLAG = '_invoice';

const FILENAME_EXTENSION_ICON = [
  'doc',
  'docx',
  'word',
  'pdf',
  'xlsx',
  'xls',
  'ppt',
  'pptx',
  'png',
  'jpg',
  'jpeg',
  'gif',
  'txt',
  'rar',
];

export interface UploadListItemProps {
  moveRow: (moveIndex: number, currentIndex: number) => void;
  file: UploadFile;
  index: number;
  onPreview: (file: UploadFile) => void;
  onNewPagePreview: (file: UploadFile) => void;
  onRemove: (file: UploadFile) => void;
  onDownload: (file: UploadFile) => void;
  showRemoveIcon?: boolean;
  showDownloadIcon?: boolean;
  showPreviewIcon?: boolean;
  operationAuth?: string;
}

const UploadListItem: FC<UploadListItemProps> = ({
  moveRow,
  file,
  index,
  onRemove,
  onDownload,
  onPreview,
  onNewPagePreview,
  showRemoveIcon,
  showPreviewIcon,
  showDownloadIcon,
  operationAuth
}) => {
  const ref = useRef<HTMLDivElement>(null);

  const { formatMessage } = useIntl();

  const [{ isOver, dropClassName }, drop] = useDrop({
    accept: type,
    collect: (monitor: any) => {
      const { index: dragIndex } = monitor.getItem() || { index: -1 };
      if (dragIndex === index) {
        return {};
      }
      return {
        isOver: monitor.isOver(),
        dropClassName: dragIndex < index ? ' drop-over-downward' : ' drop-over-upward',
      };
    },
    drop: (item: DynamicObjectAny) => {
      if (index > -1 && item.index > -1) {
        moveRow(item.index, index);
      }
    },
  });
  const [, drag] = useDrag({
    type,
    item: { index },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  });

  drop(drag(ref));

  const [showProgress, setShowProgress] = useState(false);
  const progressRafRef = useRef<any>();
  useEffect(() => {
    progressRafRef.current = setTimeout(() => {
      setShowProgress(true);
    }, 300);

    return () => {
      window.clearTimeout(progressRafRef.current);
    };
  }, []);

  const spanClassName = `${prefixCls}-span`;

  const { name } = file || {};

  const filenameExtension: string = name?.split('.').pop() || '';
  const isImg = IMG_TYPE.includes(`.${filenameExtension}`);

  const infoUploadingClass = classNames({
    [`${prefixCls}-list-item`]: true,
    [`${prefixCls}-list-item-${file.status}`]: true,
    [`${prefixCls}-list-item-list-type-text`]: true,
    "slice-file-upload": true
  });

  const actionIconRender = (
    customIcon: ReactNode,
    callback: () => void,
    prefixCls: string,
    title?: string,
  ) => {
    const btnProps: ButtonProps = {
      type: 'text',
      size: 'small',
      title,
      onClick: (e: MouseEvent<HTMLElement>) => {
        callback();
        if (isValidElement(customIcon) && customIcon.props.onClick) {
          customIcon.props.onClick(e);
        }
      },
      className: `${prefixCls}-list-item-card-actions-btn`,
    };
    if (isValidElement(customIcon)) {
      const btnIcon = cloneElement(customIcon, {
        ...customIcon.props,
        onClick: () => {},
      });

      return <Button {...btnProps} icon={btnIcon} />;
    }
    return (
      <Button {...btnProps}>
        <span>{customIcon}</span>
      </Button>
    );
  };

  const removeIcon = showRemoveIcon
    ? actionIconRender(
        <DeleteOutlined />,
        () => onRemove(file),
        prefixCls,
        formatMessage({
          id: 'upload.remove',
        }),
      )
    : null;

  const downloadIcon =
    showDownloadIcon && (file.status === 'done' || file.status === 'success')
      ? actionIconRender(
          <DownloadOutlined />,
          () => onDownload(file),
          prefixCls,
          formatMessage({
            id: 'upload.download',
          }),
        )
      : null;

  const previewIcon = showPreviewIcon
    ? actionIconRender(
        <EyeOutlined />,
        () => onPreview(file),
        prefixCls,
        formatMessage({
          id: 'upload.preview',
        }),
      )
    : null;

  const newPagePreviewIcon = showPreviewIcon && !isImg
  ? actionIconRender(
      <CopyOutlined />,
      () => onNewPagePreview(file),
      prefixCls,
      formatMessage({
        id: 'upload.preview.new.page',
      }),
    )
  : null;

  const actions = file.status !== 'uploading' && (
    <span key="actions" className={`${prefixCls}-list-item-card-actions`}>
      {operationAuth ? operationAuth.includes('AttaPreview') && previewIcon : previewIcon}
      {operationAuth ? operationAuth.includes('AttaPreview') && newPagePreviewIcon : newPagePreviewIcon}
      {operationAuth ? operationAuth.includes('AttaDownload') && file.status === 'done' && downloadIcon : file.status === 'done' && downloadIcon}
      {file?.name?.includes(NO_REMOVE_FLAG) ? null : removeIcon}
    </span>
  );

  const rootPrefixCls = 'ant';

  const listItemNameClass = classNames(`${prefixCls}-list-item-name`);

  const dom = (
    <div className={infoUploadingClass}>
      <div className={`${prefixCls}-list-item-info`}>
        <span className={spanClassName}>
          <div className={`${prefixCls}-text-icon`}>
            <span
              className={classNames({
                'file-icon': true,
                [`file-icon-${filenameExtension}`]: filenameExtension
                  ? FILENAME_EXTENSION_ICON.includes(filenameExtension)
                  : false,
              })}
            />
          </div>
          <span
            key="view"
            className={listItemNameClass}
            title={file.name}
            style={{
              width: 'auto',
              cursor: 'pointer'
            }}
            onClick={() => {
              const filenameExtension: string = file.name?.split('.').pop() || '';
              const isImg = IMG_TYPE.includes(`.${filenameExtension}`);

              isImg ? onPreview(file) : onNewPagePreview(file);
            }}
          >
            {file?.name}
          </span>
          {actions}
        </span>
      </div>

      {showProgress && (
        <CSSMotion
          motionName={`${rootPrefixCls}-fade`}
          visible={file.status === 'uploading'}
          motionDeadline={2000}
        >
          {({ className: motionClassName }) => {
            // show loading icon if upload progress listener is disabled
            const loadingProgress =
              'percent' in file ? (
                <Progress strokeWidth={2} showInfo={false} type="line" percent={file.percent} />
              ) : null;

            return (
              <div className={classNames(`${prefixCls}-list-item-progress`, motionClassName)}>
                {loadingProgress}
              </div>
            );
          }}
        </CSSMotion>
      )}
    </div>
  );

  const item =
    file.status === 'error' ? (
      <Tooltip
        title={formatMessage({
          id: 'upload.error',
        })}
        getPopupContainer={(node) => node.parentNode as HTMLElement}
      >
        {dom}
      </Tooltip>
    ) : (
      dom
    );

  return (
    <div
      ref={ref}
      className={`ant-upload-draggable-list-item ${isOver ? dropClassName : ''}`}
      style={{ cursor: 'move' }}
    >
      {item}
    </div>
  );
};

UploadListItem.defaultProps = {
  showRemoveIcon: true,
  showDownloadIcon: true,
  showPreviewIcon: true,
};

export default UploadListItem;
